﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace FasterWPF
{
    public static class KeyboardHelper
    {
        static bool AltKeyPressed = false;

        public static Key GetKeyPressedInCombinatinWithAltKey(KeyEventArgs e)
        {
            Key keyPressedInCombinationWithAlt = 0;

            if (AltKeyPressed)
            {
                AltKeyPressed = false;

                keyPressedInCombinationWithAlt = e.SystemKey;
            }

            if (e.SystemKey == Key.LeftAlt || e.SystemKey == Key.RightAlt)
            {
                AltKeyPressed = true;
            }

            return keyPressedInCombinationWithAlt;
        }
    }

    public static class ContemporaryStyle
    {
        /// <summary>
        /// Display a Custom Form Dialog. Labels and Fields may be added via the buildFormAction parameter. Will NOT display if another dialog with the SAME dialogGuid is already displaying.
        /// </summary>
        /// <param name="canVas"></param>
        /// <param name="dialogGuid"></param>
        /// <param name="caption"></param>
        /// <param name="width"></param>
        /// <param name="borderWidth"></param>
        /// <param name="borderHeight"></param>
        /// <param name="left"></param>
        /// <param name="top"></param>
        /// <param name="dialogBoxBorder"></param>
        /// <param name="dialogBoxBorderThickness"></param>
        /// <param name="borderBackground"></param>
        /// <param name="labelBackground"></param>
        /// <param name="buttonBackgrounds"></param>
        /// <param name="buttonBorders"></param>
        /// <param name="buttonOnMouseOverColors"></param>
        /// <param name="buildFormAction"></param>
        /// <returns></returns>
        public static Border ShowCustomFormDialog(Canvas canVas, string dialogGuid, string caption, double width, double borderWidth, double borderHeight, double left, double top, Brush dialogBoxBorder, Thickness dialogBoxBorderThickness, Brush borderBackground, Brush labelBackground, Brush buttonBackgrounds, Brush buttonBorders, Brush buttonOnMouseOverColors, Action<StackPanel, Border, Border, Label> buildFormAction)
        {
            double height = 149D;
            Border brd1 = new Border();
            brd1.Initialize(width, height, ContainerType.HorizontalPanel, dialogBoxBorder, dialogBoxBorderThickness, Brushes.WhiteSmoke);
            brd1.BeginSettings<Border>().SetItemBorderSettings<Border>(width, height, Brushes.Transparent, new Thickness(0)).EndSettings<Border>();

            //StackPanel
            StackPanel stkPanel1 = new StackPanel();
            stkPanel1.SetBackgroundColor(borderBackground);
            stkPanel1.Initialize(width, height, ContainerType.Grid, Orientation.Vertical);
            stkPanel1.SetCompositeGridDimensionsWithRowHt(1, 1, 50D, GridUnitType.Pixel, width, GridUnitType.Pixel);

            if (!canVas.IsCompositeOnParent<Canvas>(dialogGuid))
            {
                canVas.BeginComposite(dialogGuid)
                    .AddExisting<Border, Canvas>(0, 0, brd1)
                    .EndComposite<Canvas, CanvasArgs>(new CanvasArgs(left, top, 500));
            }

            brd1.BeginComposite()
              .AddExisting<StackPanel, Border>(0, 0, stkPanel1)
              .EndComposite<Border, BorderArgs>(null);

            stkPanel1.BeginSettings<StackPanel>()
                .SetFontOnLabel<StackPanel>(0, 0, "Calibri", 13, FontWeights.Normal, FontStyles.Normal)
                .Set<Border, StackPanel>(0, 2, "Margin", new Thickness(0, 0, 10, 7))
                .Set<Border, StackPanel>(0, 1, "HorizontalAlignment", HorizontalAlignment.Right)
                .Set<Border, StackPanel>(0, 2, "HorizontalAlignment", HorizontalAlignment.Right)
                .EndSettings<StackPanel>();

            stkPanel1.BeginComposite()
                .AddFlatButton<StackPanel>(0, 1, 21D, 21D, " X", buttonBorders, new Thickness(1), buttonBackgrounds, new CornerRadius(1), new Thickness(2, 1, 1, 1), new Thickness(0, 0, 10, 7), buttonOnMouseOverColors, (o1, e) =>
                { //CLOSE DIALOG
                    if (canVas.IsCompositeOnParent<Canvas>(dialogGuid))
                    {
                        FasterWPF.Selectors.DisposeEventsOnAllParents(stkPanel1);
                        canVas.RemoveByKey<Canvas>(dialogGuid);
                    }
                })
               .EndComposite<StackPanel, StackPanelArgs>(null);

            stkPanel1.BeginComposite()
                .AddLabel<StackPanel>(0, 0, caption, labelBackground)
                .EndComposite<StackPanel, StackPanelArgs>(null);

            Border borderButton3 = new Border();
            borderButton3.MaxHeight = 30;
            borderButton3.Initialize(double.NaN, double.NaN, ContainerType.HorizontalPanel, buttonBorders, new Thickness(2), buttonBackgrounds, new CornerRadius(10), new Thickness(0), new Thickness(1));

            borderButton3.BeginSettings<Border>()
                .SetTextPadding<Border>(0, 0, new Thickness(4))
                .SubscribeMouseSingleClickOnBorder<Border>((o1, ev1) =>
                {   //CLOSE DIALOG
                    if (canVas.IsCompositeOnParent<Canvas>(dialogGuid))
                    {
                        FasterWPF.Selectors.DisposeEventsOnAllParents(stkPanel1);
                        canVas.RemoveByKey<Canvas>(dialogGuid);
                    }
                })
                .EndSettings<Border>();

            borderButton3.SetMouseOverColorOnBorder(buttonOnMouseOverColors);

            borderButton3.BeginComposite()
                .AddText<Border>(0, 0, "  OK  ")
                .EndComposite<Border, BorderArgs>(null);

            stkPanel1.BeginComposite()
                     .AddExisting<Border, StackPanel>(0, 2, borderButton3)
                     .EndComposite<StackPanel, StackPanelArgs>(null);

            brd1.Width = borderWidth;
            brd1.Height = borderHeight;

            var act1 = new Action<FrameworkElement>((FrameworkElement fe) =>
                {
                    if (fe is StackPanel)
                    {
                        SettingsManager.BeginSettings((StackPanel)fe).Set<Label, StackPanel>("Width", 50.0).Set<Label, StackPanel>("Height", 50.0).EndSettings();

                        //To insert some new elements we have to re-arrange the OK Button by removing and then re-adding it further below
                        var cancelButton = (Border)FasterWPF.CommonExt.GetChildLookupDictionary<StackPanel>((StackPanel)fe).ElementAt(0).Value;
                        var okButton = (Border)FasterWPF.CommonExt.GetChildLookupDictionary<StackPanel>((StackPanel)fe).ElementAt(2).Value;
                        string myKey = FasterWPF.CommonExt.GetKey((Border)okButton.GetBorderFromChildElement<Border>());
                        FasterWPF.CommonExt.RemoveByKey((StackPanel)fe, myKey);

                        var theLabel = (Label)FasterWPF.CommonExt.GetChildLookupDictionary<StackPanel>((StackPanel)fe).ElementAt(1).Value;
                        buildFormAction(stkPanel1, okButton, cancelButton, theLabel);
                         //Add OK button back                                                            
                        FasterWPF.CommonExt.BeginComposite<StackPanel>(stkPanel1).AddExisting<Border, StackPanel>(0, 2, okButton).EndComposite<StackPanel, StackPanelArgs>(null);
                    }
                });

            brd1.ActOnParentFrameworkElements(act1);
            return brd1;
        }

        /// <summary>
        /// Display an OK Dialog. Will NOT display if another dialog with the SAME dialogGuid is already displaying.
        /// </summary>
        /// <param name="canVas"></param>
        /// <param name="dialogGuid"></param>
        /// <param name="caption"></param>
        /// <param name="width"></param>
        /// <param name="left"></param>
        /// <param name="top"></param>
        /// <param name="dialogBoxBorder"></param>
        /// <param name="dialogBoxBorderThickness"></param>
        /// <param name="borderBackground"></param>
        /// <param name="labelBackground"></param>
        /// <param name="buttonBackgrounds"></param>
        /// <param name="buttonBorders"></param>
        /// <param name="buttonOnMouseOverColors"></param>
        /// <returns></returns>
        public static Border ShowOKDialog(Canvas canVas, string dialogGuid, string caption, double width, double left, double top, Brush dialogBoxBorder, Thickness dialogBoxBorderThickness, Brush borderBackground, Brush labelBackground, Brush buttonBackgrounds, Brush buttonBorders, Brush buttonOnMouseOverColors)
        {
            double height = 149D;
            Border brd1 = new Border();
            brd1.Initialize(width, height, ContainerType.HorizontalPanel, dialogBoxBorder, dialogBoxBorderThickness, Brushes.WhiteSmoke);
            brd1.BeginSettings<Border>().SetItemBorderSettings<Border>(width, height, Brushes.Transparent, new Thickness(0)).EndSettings<Border>();

            //StackPanel
            StackPanel stkPanel1 = new StackPanel();
            stkPanel1.SetBackgroundColor(borderBackground);
            stkPanel1.Initialize(width, height, ContainerType.Grid, Orientation.Vertical);
            stkPanel1.SetCompositeGridDimensionsWithRowHt(1, 1, 50D, GridUnitType.Pixel, width, GridUnitType.Pixel);

            if (!canVas.IsCompositeOnParent<Canvas>(dialogGuid))
            {
                canVas.BeginComposite(dialogGuid)
                    .AddExisting<Border, Canvas>(0, 0, brd1)
                    .EndComposite<Canvas, CanvasArgs>(new CanvasArgs(left, top, 500));
            }

            brd1.BeginComposite()
              .AddExisting<StackPanel, Border>(0, 0, stkPanel1)
              .EndComposite<Border, BorderArgs>(null);

            stkPanel1.BeginSettings<StackPanel>()
                .SetFontOnLabel<StackPanel>(0, 0, "Calibri", 13, FontWeights.Normal, FontStyles.Normal)
                .Set<Border, StackPanel>(0, 2, "Margin", new Thickness(0, 0, 10, 7))
                .Set<Border, StackPanel>(0, 1, "HorizontalAlignment", HorizontalAlignment.Right)
                .Set<Border, StackPanel>(0, 2, "HorizontalAlignment", HorizontalAlignment.Right)
                .EndSettings<StackPanel>();

            stkPanel1.BeginComposite()
                .AddAnything<TextBox, StackPanel>(0, 0).ModifyAtXY<TextBox, StackPanel>(0, 0, txtBox =>
                {
                     txtBox.Height = 1.0D;
                })
                .AddFlatButton<StackPanel>(0, 1, 21D, 21D, " X", buttonBorders, new Thickness(1), buttonBackgrounds, new CornerRadius(1), new Thickness(2, 1, 1, 1), new Thickness(0, 0, 10, 7), buttonOnMouseOverColors, (o1, e) =>
                { //CLOSE DIALOG
                    if (canVas.IsCompositeOnParent<Canvas>(dialogGuid))
                    {
                        FasterWPF.Selectors.DisposeEventsOnAllParents(stkPanel1);
                        canVas.RemoveByKey<Canvas>(dialogGuid);
                    }
                })
               .EndComposite<StackPanel, StackPanelArgs>(null);

            stkPanel1.BeginComposite()
                .AddLabel<StackPanel>(0, 0, caption, labelBackground)
                .EndComposite<StackPanel, StackPanelArgs>(null);

            Border borderButton3 = new Border();
            borderButton3.MaxHeight = 30;
            borderButton3.Initialize(double.NaN, double.NaN, ContainerType.HorizontalPanel, buttonBorders, new Thickness(2), buttonBackgrounds, new CornerRadius(10), new Thickness(0), new Thickness(1));

            borderButton3.BeginSettings<Border>()
                .SetTextPadding<Border>(0, 0, new Thickness(4))
                .SubscribeMouseSingleClickOnBorder<Border>((o1, ev1) =>
                {   //CLOSE DIALOG
                    if (canVas.IsCompositeOnParent<Canvas>(dialogGuid))
                    {
                        FasterWPF.Selectors.DisposeEventsOnAllParents(stkPanel1);
                        canVas.RemoveByKey<Canvas>(dialogGuid);
                    }
                })
                .EndSettings<Border>();

            borderButton3.SetMouseOverColorOnBorder(buttonOnMouseOverColors);

            borderButton3.BeginComposite()
                .AddText<Border>(0, 0, "  OK  ")
                .EndComposite<Border, BorderArgs>(null);

            stkPanel1.BeginComposite()
                     .AddExisting<Border, StackPanel>(0, 2, borderButton3)
                     .EndComposite<StackPanel, StackPanelArgs>(null);

            //Capture ESC Key Input and Close Dialog
            Action<EventPattern<KeyEventArgs>> keyInputs = (eventPattern) =>
            {
                //CLOSE DIALOG
                if (eventPattern.EventArgs.Key == Key.Escape || eventPattern.EventArgs.Key == Key.Enter)
                {
                    if (canVas.IsCompositeOnParent<Canvas>(dialogGuid))
                    {
                        FasterWPF.Selectors.DisposeEventsOnAllParents(stkPanel1);
                        canVas.RemoveByKey<Canvas>(dialogGuid);
                    }
                }
            };

            FasterWPF.CommonExt.SubscribeEventOnParent<StackPanel, KeyEventArgs>(stkPanel1, "PreviewKeyDown", keyInputs);
         
            var txtBox1 = FasterWPF.Selectors.SelectFrameworkElementsByType<TextBox>(stkPanel1).First();

            System.Windows.Forms.SendKeys.SendWait("{Tab}");
            Keyboard.Focus(txtBox1);
            txtBox1.Focus();

            return brd1;
        }

        /// <summary>
        /// Display a YES-NO-CANCEL Dialog. Will NOT display if another dialog with the SAME dialogGuid is already displaying.
        /// </summary>
        /// <param name="canVas"></param>
        /// <param name="dialogGuid"></param>
        /// <param name="caption"></param>
        /// <param name="width"></param>
        /// <param name="left"></param>
        /// <param name="top"></param>
        /// <param name="dialogBoxBorder"></param>
        /// <param name="dialogBoxBorderThickness"></param>
        /// <param name="borderBackground"></param>
        /// <param name="labelBackground"></param>
        /// <param name="buttonBackgrounds"></param>
        /// <param name="buttonBorders"></param>
        /// <param name="buttonOnMouseOverColors"></param>
        /// <param name="resultCallback"></param>
        /// <returns></returns>
        public static Border ShowYesNoCancelDialog(Canvas canVas, string dialogGuid, string caption, double width, double left, double top, Brush dialogBoxBorder, Thickness dialogBoxBorderThickness, Brush borderBackground, Brush labelBackground, Brush buttonBackgrounds, Brush buttonBorders, Brush buttonOnMouseOverColors, Action<bool> resultCallback)
        {
            double height = 149D;
            Border brd1 = new Border();
            brd1.Initialize(width, height, ContainerType.HorizontalPanel, dialogBoxBorder, dialogBoxBorderThickness, Brushes.WhiteSmoke);
            brd1.BeginSettings<Border>().SetItemBorderSettings<Border>(width, height, Brushes.Transparent, new Thickness(0)).EndSettings<Border>();

            //StackPanel
            StackPanel stkPanel1 = new StackPanel();
            stkPanel1.SetBackgroundColor(borderBackground);
            stkPanel1.Initialize(width, height, ContainerType.Grid, Orientation.Vertical);
            stkPanel1.SetCompositeGridDimensionsWithRowHt(1, 1, 50D, GridUnitType.Pixel, width, GridUnitType.Pixel);

            if (!canVas.IsCompositeOnParent<Canvas>(dialogGuid))
            {
                canVas.BeginComposite(dialogGuid)
                    .AddExisting<Border, Canvas>(0, 0, brd1)
                    .EndComposite<Canvas, CanvasArgs>(new CanvasArgs(left, top, 500));
            }

            brd1.BeginComposite()
              .AddExisting<StackPanel, Border>(0, 0, stkPanel1)
              .EndComposite<Border, BorderArgs>(null);

            stkPanel1.BeginSettings<StackPanel>()
                .SetFontOnLabel<StackPanel>(0, 0, "Calibri", 13, FontWeights.Normal, FontStyles.Normal)
                .Set<Border, StackPanel>(0, 2, "Margin", new Thickness(0, 0, 10, 7))
                .Set<Border, StackPanel>(0, 1, "HorizontalAlignment", HorizontalAlignment.Right)
                .Set<Border, StackPanel>(0, 2, "HorizontalAlignment", HorizontalAlignment.Right)
                .EndSettings<StackPanel>();

            stkPanel1.BeginComposite()
                .AddAnything<TextBox, StackPanel>(0, 0).ModifyAtXY<TextBox, StackPanel>(0, 0, txtBox =>
                {
                    txtBox.Height = 1.0D;
                })
                .AddFlatButton<StackPanel>(0, 1, 21D, 21D, " X", buttonBorders, new Thickness(1), buttonBackgrounds, new CornerRadius(1), new Thickness(2, 1, 1, 1), new Thickness(0, 0, 10, 7), buttonOnMouseOverColors, (o1, e) =>
                { //CLOSE DIALOG
                    if (canVas.IsCompositeOnParent<Canvas>(dialogGuid))
                    {
                        FasterWPF.Selectors.DisposeEventsOnAllParents(stkPanel1);
                        canVas.RemoveByKey<Canvas>(dialogGuid);
                        resultCallback(false);
                    }
                })
               .EndComposite<StackPanel, StackPanelArgs>(null);

            stkPanel1.BeginComposite()
                .AddLabel<StackPanel>(0, 0, caption, labelBackground)
                .EndComposite<StackPanel, StackPanelArgs>(null);

            //OK BUTTON
            Border borderButton3 = new Border();
            borderButton3.MaxHeight = 30;
            borderButton3.Margin = new Thickness(0.0, 0.0, 3.0, 0.0);
            borderButton3.Initialize(double.NaN, double.NaN, ContainerType.HorizontalPanel, buttonBorders, new Thickness(2), buttonBackgrounds, new CornerRadius(10), new Thickness(0), new Thickness(1));

            borderButton3.BeginSettings<Border>()
                .SetTextPadding<Border>(0, 0, new Thickness(4))
                .SubscribeMouseSingleClickOnBorder<Border>((o1, ev1) =>
                {   //CLOSE DIALOG
                    if (canVas.IsCompositeOnParent<Canvas>(dialogGuid))
                    {
                        FasterWPF.Selectors.DisposeEventsOnAllParents(stkPanel1);
                        canVas.RemoveByKey<Canvas>(dialogGuid);
                        resultCallback(true);
                    }
                })
                .EndSettings<Border>();

            borderButton3.SetMouseOverColorOnBorder(buttonOnMouseOverColors);

            borderButton3.BeginComposite()
                .AddText<Border>(0, 0, "  Yes  ")
                .EndComposite<Border, BorderArgs>(null);
            
            //CANCEL BUTTON
            Border borderButton5 = new Border();
            borderButton5.MaxHeight = 30;
            borderButton5.Margin = new Thickness(0.0, 0.0, 5.0, 0.0);
            borderButton5.Initialize(double.NaN, double.NaN, ContainerType.HorizontalPanel, buttonBorders, new Thickness(2), buttonBackgrounds, new CornerRadius(10), new Thickness(0), new Thickness(1));

            borderButton5.BeginSettings<Border>()
                .SetTextPadding<Border>(0, 0, new Thickness(4))
                .SubscribeMouseSingleClickOnBorder<Border>((o1, ev1) =>
                {   //CLOSE DIALOG
                    if (canVas.IsCompositeOnParent<Canvas>(dialogGuid))
                    {
                        FasterWPF.Selectors.DisposeEventsOnAllParents(stkPanel1);
                        canVas.RemoveByKey<Canvas>(dialogGuid);
                        resultCallback(false);
                    }
                })
                .EndSettings<Border>();

            borderButton5.SetMouseOverColorOnBorder(buttonOnMouseOverColors);

            borderButton5.BeginComposite()
                .AddText<Border>(0, 0, "  No  ")
                .EndComposite<Border, BorderArgs>(null);
            
            DockPanel ccPanel5 = new DockPanel();
            ccPanel5.Initialize(width, 33.00, ContainerType.ContentControlPanel);
            ccPanel5.LastChildFill=false;

            Rectangle shim = new Rectangle();
            shim.Fill = Brushes.Transparent;
            shim.Stroke = Brushes.Transparent;
            shim.Width = 10.0;
            shim.Height = 1.0;

            ccPanel5.BeginComposite()
                     .AddExisting<Rectangle, DockPanel>(0, 0, shim)
                     .EndComposite<DockPanel, DockArgs>(new DockArgs(Dock.Right));    

            ccPanel5.BeginComposite()
                     .AddExisting<Border, DockPanel>(0, 0, borderButton5)
                     .EndComposite<DockPanel, DockArgs>(new DockArgs(Dock.Right));                
                
            ccPanel5.BeginComposite()
                    .AddExisting<Border, DockPanel>(0, 0, borderButton3)
                    .EndComposite<DockPanel, DockArgs>(new DockArgs(Dock.Right));
            
            //Capture ESC Key Input and Close Dialog
            Action<EventPattern<KeyEventArgs>> keyInputs = (eventPattern) =>
                {
                    //CLOSE DIALOG
                    if (eventPattern.EventArgs.Key == Key.Escape) 
                    {                              
                         if (canVas.IsCompositeOnParent<Canvas>(dialogGuid))
                         {
                                FasterWPF.Selectors.DisposeEventsOnAllParents(stkPanel1);
                                canVas.RemoveByKey<Canvas>(dialogGuid);
                                resultCallback(false);
                         }
                    }
                    if (eventPattern.EventArgs.Key == Key.Enter)
                    {
                        if (canVas.IsCompositeOnParent<Canvas>(dialogGuid))
                        {
                            FasterWPF.Selectors.DisposeEventsOnAllParents(stkPanel1);
                            canVas.RemoveByKey<Canvas>(dialogGuid);
                            resultCallback(true);
                        }
                    }
                };

            FasterWPF.CommonExt.SubscribeEventOnParent(stkPanel1, "PreviewKeyDown", keyInputs);
            
            stkPanel1.BeginComposite()
                     .AddExisting<DockPanel, StackPanel>(0, 2, ccPanel5)
                     .EndComposite<StackPanel, StackPanelArgs>(null);

            var txtBox1 = FasterWPF.Selectors.SelectFrameworkElementsByType<TextBox>(stkPanel1).First();

            System.Windows.Forms.SendKeys.SendWait("{Tab}");
            Keyboard.Focus(txtBox1);
            txtBox1.Focus();
            return brd1;
        }

        /// <summary>
        /// Create a ContentControl applying the ContemporaryStyle
        /// </summary>
        /// <param name="txb"></param>
        /// <returns></returns>
        public static ContentControl NewTabHeader(TabControl tbCtl, Brush foreground, Brush tabLabelBackground, Brush colorOfTheX, Brush tabItemUnderlineColor, string tabText, bool includeColoredLine, Action<object, MouseButtonEventArgs> closeAction)
        {
            StackPanel stkPnl = new StackPanel();
            stkPnl.Orientation = Orientation.Horizontal;
            stkPnl.Children.Add(new TextBlock(new Run(tabText) { FontFamily = new System.Windows.Media.FontFamily("Tahoma"), FontSize = 13D }) { Foreground = foreground, Margin = new Thickness(2, 2, 3, 2) });
            TextBlock txBlock = new TextBlock(new Run("X") { FontFamily = new System.Windows.Media.FontFamily("Tahoma"), FontWeight = FontWeights.ExtraBold, FontSize = 14D }) { Foreground = colorOfTheX, Margin = new Thickness(1, 2, 3, 2), ToolTip = "Close", };
            stkPnl.Children.Add(txBlock);
            txBlock.PreviewMouseDown += (o, e) => { closeAction(tbCtl, e); };
            
            ContentControl cc = new ContentControl()
            {
                Content = (
                   new Border() {
                       Background = tabLabelBackground,
                       BorderThickness = new Thickness(0, (includeColoredLine ? 2 : 0), 0, ((!includeColoredLine) ? 2 : 0)), 
                       BorderBrush = tabItemUnderlineColor, 
                       Child = stkPnl })
            };

            return cc;
        }
        
        public static void CreateGroupBoxHeader(this GroupBox grpbx, string headerTitle, Brush headerBackground, Brush foreground, string titleFont, double titleFontSize, FontWeight titleFontWeight, FontStyle titleFontStyle, Brush borderBrush, Thickness borderThickness)
        {
            Label titleLabel = new Label();
            titleLabel.Content = headerTitle;
            titleLabel.Background = headerBackground;
            titleLabel.Foreground = foreground;
            FontSettings fontSettings = FontExt.CreateFont(titleFont, titleFontSize, titleFontWeight, titleFontStyle);
            FontExt.ApplyFontSettings(fontSettings, titleLabel);
            grpbx.Header = titleLabel;
            grpbx.BorderBrush = borderBrush;
            grpbx.BorderThickness = borderThickness;
        }

        /// <summary>
        /// Apply ContemporaryStyle to ScrollViewer
        /// </summary>
        /// <param name="txb"></param>
        /// <returns></returns>
        public static void ApplyToScrollViewer(ScrollViewer source, string mouseOverColor, string pressedColor, string backgroundColor)
        {
            source.Apply(settings =>
               {
                   settings

                       ////VERTICAL SCROLLBAR
                       .SetVerticalScrollBarColor(Brushes.WhiteSmoke)
                       .SetVerticalScrollUpButtonColors("WhiteSmoke", mouseOverColor, pressedColor, pressedColor, pressedColor, "0", "Gray", new Thickness(1), "Black", mouseOverColor, "M 0 4 L 7 4 L 3.5 0 Z")
                       .SetVerticalPageUpButtonColors("#DDDDDD", "Gray", "Gray", "#DDDDDD") //, "2", "White", new Thickness(3, 3, 3, 3))
                       .SetVerticalPageDownButtonColors("#DDDDDD", "#DDDDDD", "Gray", "Gray") //,"5", "Gray", new Thickness(3, 3, 3, 3))
                       .SetVerticalScrollDownButtonColors("WhiteSmoke", mouseOverColor, pressedColor, pressedColor, pressedColor, "0", "Gray", new Thickness(1), "Black", mouseOverColor, "M 0 0 L 3.5 4 L 7 0 Z")
                       .SetVerticalScrollThumbColors(backgroundColor, mouseOverColor, mouseOverColor, "#DDDDDD", "1", "1")

                       //HORIZONTAL SCROLLBAR
                       .SetHorizontalScrollBarColor(Brushes.WhiteSmoke)
                       .SetHorizontalScrollRightButtonColors("WhiteSmoke", mouseOverColor, pressedColor, pressedColor, pressedColor, "0", "#FFEE", new Thickness(1), "Black", mouseOverColor, "M 0 0 L 4 4 L 0 8 Z")
                       .SetHorizontalPageRightButtonColors("#DDDDDD", "#DDDDDD", "Gray", "Gray") //, "#FFEE", "0", new Thickness(0, 0, 0, 0))
                       .SetHorizontalPageLeftButtonColors("#DDDDDD", "Gray", "Gray", "#DDDDDD") // , "#FFEE", "0", new Thickness(0, 0, 0, 0))
                       .SetHorizontalScrollLeftButtonColors("WhiteSmoke", mouseOverColor, pressedColor, pressedColor, pressedColor, "0", "#FFEE", new Thickness(1), "Black", mouseOverColor, "M 4 0 L 4 8 L 0 4 Z")
                       .SetHorizontalScrollThumbColors(backgroundColor, mouseOverColor, mouseOverColor, "#DDDDDD", "1", "1")

                       .SetScrollViewerCornerRectangleColor(Brushes.White)
                       .SetVerticalScrollDownStepDelayAndInterval(1, 30, 3)
                       .SetVerticalPageDownStepDelayAndInterval(25, 30, 3)
                       .SetHorizontalScrollRightStepDelayAndInterval(10, 30, 3)
                       .SetHorizontalPageRightStepDelayAndInterval(25, 30, 3)
                       .SetVerticalThumbStep(1)
                       .SetHorizontalThumbStep(1)
                       .SetVerticalPageUpStepDelayAndInterval(25, 30, 3)
                       .SetVerticalScrollUpStepDelayAndInterval(1, 30, 3)
                       .SetHorizontalPageLeftStepDelayAndInterval(25, 30, 3)
                       .SetHorizontalScrollLeftStepDelayAndInterval(10, 30, 3);
               });
        }

        /// <summary>
        /// Apply ContemporaryStyle to T that has a ScrollViewer
        /// </summary>
        /// <param name="txb"></param>
        /// <returns></returns>
        public static void ApplyToScrollViewer<T>(T sourceWithScrollViewer, string mouseOverColor, string pressedColor, string backgroundColor) 
            where T : FrameworkElement
        {
            sourceWithScrollViewer.Apply(settings =>
            {
                settings

                    ////VERTICAL SCROLLBAR
                    .SetVerticalScrollBarColor(Brushes.WhiteSmoke)
                    .SetVerticalScrollUpButtonColors("WhiteSmoke", mouseOverColor, pressedColor, pressedColor, pressedColor, "0", "Gray", new Thickness(1), "Black", mouseOverColor, "M 0 4 L 7 4 L 3.5 0 Z")
                    .SetVerticalPageUpButtonColors("#DDDDDD", "Gray", "Gray", "#DDDDDD") //, "2", "White", new Thickness(3, 3, 3, 3))
                    .SetVerticalPageDownButtonColors("#DDDDDD", "#DDDDDD", "Gray", "Gray") //,"5", "Gray", new Thickness(3, 3, 3, 3))
                    .SetVerticalScrollDownButtonColors("WhiteSmoke", mouseOverColor, pressedColor, pressedColor, pressedColor, "0", "Gray", new Thickness(1), "Black", mouseOverColor, "M 0 0 L 3.5 4 L 7 0 Z")
                    .SetVerticalScrollThumbColors(backgroundColor, mouseOverColor, mouseOverColor, "#DDDDDD", "1", "1")

                    //HORIZONTAL SCROLLBAR
                    .SetHorizontalScrollBarColor(Brushes.WhiteSmoke)
                    .SetHorizontalScrollRightButtonColors("WhiteSmoke", mouseOverColor, pressedColor, pressedColor, pressedColor, "0", "#FFEE", new Thickness(1), "Black", mouseOverColor, "M 0 0 L 4 4 L 0 8 Z")
                    .SetHorizontalPageRightButtonColors("#DDDDDD", "#DDDDDD", "Gray", "Gray") //, "#FFEE", "0", new Thickness(0, 0, 0, 0))
                    .SetHorizontalPageLeftButtonColors("#DDDDDD", "Gray", "Gray", "#DDDDDD") // , "#FFEE", "0", new Thickness(0, 0, 0, 0))
                    .SetHorizontalScrollLeftButtonColors("WhiteSmoke", mouseOverColor, pressedColor, pressedColor, pressedColor, "0", "#FFEE", new Thickness(1), "Black", mouseOverColor, "M 4 0 L 4 8 L 0 4 Z")
                    .SetHorizontalScrollThumbColors(backgroundColor, mouseOverColor, mouseOverColor, "#DDDDDD", "1", "1")

                    .SetScrollViewerCornerRectangleColor(Brushes.White)

                    //these logical scroll settings are deprecated. I force physical scrolling going forward!
                    .SetVerticalScrollDownStepDelayAndInterval(1, 30, 3)
                    .SetVerticalPageDownStepDelayAndInterval(25, 30, 3)
                    .SetHorizontalScrollRightStepDelayAndInterval(10, 30, 3)
                    .SetHorizontalPageRightStepDelayAndInterval(25, 30, 3)
                    .SetVerticalThumbStep(1)
                    .SetHorizontalThumbStep(1)
                    .SetVerticalPageUpStepDelayAndInterval(25, 30, 3)
                    .SetVerticalScrollUpStepDelayAndInterval(1, 30, 3)
                    .SetHorizontalPageLeftStepDelayAndInterval(25, 30, 3)
                    .SetHorizontalScrollLeftStepDelayAndInterval(10, 30, 3);
            });
        }

        /// <summary>
        /// Create a Label via FrameworkElementFactory for use with ListBox or ListView Group Description
        /// </summary>
        /// <param name="txb"></param>
        /// <returns></returns>
        public static FrameworkElementFactory CreateLabelForGroupItem(double height, double width, double fontSize, FontWeight fontWeight, Thickness margin, Brush foreground, Brush background, Brush borderBrush, Thickness borderThickness, HorizontalAlignment horizontalAlignment)
        {
           FrameworkElementFactory fefr = new FrameworkElementFactory(typeof(Label))
                            .SetProperty(Label.FontWeightProperty, fontWeight)
                            .SetProperty(Label.MarginProperty, margin)
                            .SetProperty(Label.HeightProperty, height)
                            .SetProperty(Label.WidthProperty, width)
                            .SetProperty(Label.FontSizeProperty, fontSize)
                            .SetProperty(Label.ForegroundProperty, foreground)
                            .SetProperty(Label.BackgroundProperty, background)
                            .SetProperty(Label.BorderBrushProperty, borderBrush)
                            .SetProperty(Label.BorderThicknessProperty, borderThickness)
                            .SetProperty(Label.HorizontalAlignmentProperty, horizontalAlignment)
                            .SetProperty(Label.ContentProperty, new Binding() { Path = new PropertyPath("Tag"), RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(Expander), 1) });

           return fefr;
        }
                    
        /// <summary>
        /// Create Expander for use with ListBox or ListView Group Description. Set factoryLabel to null if passing into method SetGroupExpanderFrameworkElementFactory.
        /// </summary>
        /// <param name="txb"></param>
        /// <returns></returns>
        public static FrameworkElementFactory CreateExpanderForGroupItem(FrameworkElementFactory factoryLabel, bool isExpanded, Brush borderBrush, Thickness borderThickness)
        {
            FrameworkElementFactory factoryExpander = new FrameworkElementFactory(typeof(Expander))
                        .SetProperty(Expander.IsExpandedProperty, isExpanded)
                        .SetProperty(Expander.BorderBrushProperty, borderBrush)
                        .SetProperty(Expander.BorderThicknessProperty, borderThickness);

            if (factoryLabel != null)
            {
                DataTemplate templateForLabel = new DataTemplate(typeof(GroupItem));
                DataTemplate templateForItemsControl = new DataTemplate(typeof(ContentControl));

                MultiBinding mb25 = new MultiBinding();
                mb25.Bindings.Add(new Binding("Name"));
                mb25.Bindings.Add(new Binding("ItemCount"));
                GroupLabelConverter glcon25 = new GroupLabelConverter();
                mb25.Converter = glcon25;

                templateForLabel.VisualTree = factoryLabel;

                FrameworkElementFactory factoryPresenter = new FrameworkElementFactory(typeof(ItemsControl));
                factoryPresenter.SetValue(ItemsControl.ItemsSourceProperty, new Binding() { Path = new PropertyPath("Content"), RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(Expander), 1) });
                templateForItemsControl.VisualTree = factoryPresenter;

                factoryExpander.SetValue(Expander.HeaderTemplateProperty, templateForLabel);
                factoryExpander.SetValue(Expander.ContentTemplateProperty, templateForItemsControl);
                factoryExpander.SetValue(Expander.TagProperty, mb25);
                factoryExpander.SetValue(Expander.ContentProperty, new Binding() { Path = new PropertyPath("Items") });
            }
                    
            return factoryExpander;
        }

        /// <summary>
        /// Create Expander for use with ListBox or ListView Group Description. Set factoryLabel to null if passing into method SetGroupExpanderFrameworkElementFactory.
        /// </summary>
        /// <param name="txb"></param>
        /// <returns></returns>
        public static FrameworkElementFactory CreateExpanderForGroupItem(FrameworkElementFactory factoryLabel, bool isExpanded, Brush borderBrush, Thickness borderThickness, string circleColor, string arrowColor, string mouseOverCircleColor, string mouseOverArrowColor, string pressedCircleColor, string pressedArrowColor, string headerBackgroundColor, FasterWPF.ExpanderExt.Shape es)
        {
            FrameworkElementFactory factoryExpander = new FrameworkElementFactory(typeof(Expander))
                        .SetProperty(Expander.IsExpandedProperty, isExpanded)
                        .SetProperty(Expander.BorderBrushProperty, borderBrush)
                        .SetProperty(Expander.TemplateProperty, ExpanderExt.ApplyExpanderStrategyFull(circleColor, arrowColor, mouseOverCircleColor, mouseOverArrowColor, pressedCircleColor, pressedArrowColor, headerBackgroundColor, es))
                        .SetProperty(Expander.BorderThicknessProperty, borderThickness);

            if (factoryLabel != null)
            {
                DataTemplate templateForLabel = new DataTemplate(typeof(GroupItem));
                DataTemplate templateForItemsControl = new DataTemplate(typeof(ContentControl));

                MultiBinding mb25 = new MultiBinding();
                mb25.Bindings.Add(new Binding("Name"));
                mb25.Bindings.Add(new Binding("ItemCount"));
                GroupLabelConverter glcon25 = new GroupLabelConverter();
                mb25.Converter = glcon25;

                templateForLabel.VisualTree = factoryLabel;

                FrameworkElementFactory factoryPresenter = new FrameworkElementFactory(typeof(ItemsControl));
                factoryPresenter.SetValue(ItemsControl.ItemsSourceProperty, new Binding() { Path = new PropertyPath("Content"), RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(Expander), 1) });
                templateForItemsControl.VisualTree = factoryPresenter;

                factoryExpander.SetValue(Expander.HeaderTemplateProperty, templateForLabel);
                factoryExpander.SetValue(Expander.ContentTemplateProperty, templateForItemsControl);
                factoryExpander.SetValue(Expander.TagProperty, mb25);
                factoryExpander.SetValue(Expander.ContentProperty, new Binding() { Path = new PropertyPath("Items") });
            }

            return factoryExpander;
        }

        /// <summary>
        /// Create Expander for use with ListBox or ListView Group Description. Set factoryLabel to null if passing into method SetGroupExpanderFrameworkElementFactory.
        /// </summary>
        /// <param name="txb"></param>
        /// <returns></returns>
        public static FrameworkElementFactory CreateExpanderForGroupItem(FrameworkElementFactory factoryLabel, bool isExpanded, Brush borderBrush, Thickness borderThickness, string circleColor, string arrowColor, string mouseOverCircleColor, string mouseOverArrowColor, string pressedCircleColor, string pressedArrowColor, string headerBackgroundColor, string expandedArrowGeometryPath, string collapsedArrowGeometryPath, FasterWPF.ExpanderExt.Shape es)
        {
            FrameworkElementFactory factoryExpander = new FrameworkElementFactory(typeof(Expander))
                        .SetProperty(Expander.IsExpandedProperty, isExpanded)
                        .SetProperty(Expander.BorderBrushProperty, borderBrush)
                        .SetProperty(Expander.TemplateProperty, ExpanderExt.ApplyExpanderStrategyFull(circleColor, arrowColor, mouseOverCircleColor, mouseOverArrowColor, pressedCircleColor, pressedArrowColor, headerBackgroundColor, expandedArrowGeometryPath, collapsedArrowGeometryPath, es))
                        .SetProperty(Expander.BorderThicknessProperty, borderThickness);

            if (factoryLabel != null)
            {
                DataTemplate templateForLabel = new DataTemplate(typeof(GroupItem));
                DataTemplate templateForItemsControl = new DataTemplate(typeof(ContentControl));

                MultiBinding mb25 = new MultiBinding();
                mb25.Bindings.Add(new Binding("Name"));
                mb25.Bindings.Add(new Binding("ItemCount"));
                GroupLabelConverter glcon25 = new GroupLabelConverter();
                mb25.Converter = glcon25;

                templateForLabel.VisualTree = factoryLabel;

                FrameworkElementFactory factoryPresenter = new FrameworkElementFactory(typeof(ItemsControl));
                factoryPresenter.SetValue(ItemsControl.ItemsSourceProperty, new Binding() { Path = new PropertyPath("Content"), RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(Expander), 1) });
                templateForItemsControl.VisualTree = factoryPresenter;

                factoryExpander.SetValue(Expander.HeaderTemplateProperty, templateForLabel);
                factoryExpander.SetValue(Expander.ContentTemplateProperty, templateForItemsControl);
                factoryExpander.SetValue(Expander.TagProperty, mb25);
                factoryExpander.SetValue(Expander.ContentProperty, new Binding() { Path = new PropertyPath("Items") });
            }

            return factoryExpander;
        }

        /// <summary>
        /// Create GroupItem Style for use with ListBox or ListView Group Description
        /// </summary>
        /// <param name="txb"></param>
        /// <returns></returns>
        public static Style CreateStyleForGroupItem(FrameworkElementFactory factoryExpander, Thickness margin )
        {
            ControlTemplate templateForExpander = new ControlTemplate(typeof(GroupItem));

            Style myStyle = new Style(typeof(GroupItem));
            Setter setter = new Setter();
            setter.Property = GroupItem.MarginProperty;
            setter.Value = margin;
            myStyle.Setters.Add(setter);

            Setter setterTemplate = new Setter();
            setterTemplate.Property = GroupItem.TemplateProperty;
            setterTemplate.Value = templateForExpander;
            myStyle.Setters.Add(setterTemplate);

            templateForExpander.VisualTree = factoryExpander;

            return myStyle;
        }
    }//end of class
}//end of namespace
